package com.sikaryofficial.file.service;

import com.alibaba.nacos.common.utils.IoUtils;
import com.sikaryofficial.common.core.utils.file.FileTypeUtils;
import com.sikaryofficial.common.core.utils.file.MimeTypeUtils;
import com.sikaryofficial.file.config.MinioConfig;
import com.sikaryofficial.file.utils.CompressionUtils;
import com.sikaryofficial.file.utils.FileUploadUtils;
import com.sikaryofficial.system.api.domain.SysFile;
import com.sikaryofficial.system.api.model.FileMergeReq;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.errors.ErrorResponseException;
import io.minio.errors.InsufficientDataException;
import io.minio.errors.InternalException;
import io.minio.errors.InvalidResponseException;
import io.minio.errors.ServerException;
import io.minio.errors.XmlParserException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.MathContext;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Objects;

/**
 * Minio 文件存储
 *
 * @author ruoyi
 */
@Primary
@Service
@Slf4j
public class MinioSysFileServiceImpl implements ISysFileService {
    private static final int UNIT_KB = 1024;
    private static final double KILOBYTE = 1024.0;
    @Autowired
    private MinioConfig minioConfig;
    @Autowired
    private MinioClient client;
    @Value("${custom.minio.hasCompress}")
    private Boolean hasCompress;
    @Resource
    private FfmpegProcess ffmpegProcess;

    @Override
    public SysFile uploadVideo(MultipartFile multipartFile) throws Exception {
        return ffmpegProcess.uploadVideo(multipartFile);
    }

    @Override
    public  SysFile videoAndAudioMerge(FileMergeReq req) throws Exception{
        return ffmpegProcess.videoAndAudioMerge(req);
    }

    /**
     * Minio文件上传接口
     *
     * @param file 上传的文件
     * @return 访问地址
     * @throws Exception
     */
    @Override
    public String uploadFile(MultipartFile file) throws Exception {
        String fileName = FileUploadUtils.extractFilename(file);
        // 文件校验
        FileUploadUtils.assertAllowedWithExt(file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
        // 判定是否为图片,如果是则进行压缩
        String extension = FileTypeUtils.getExtension(file);
        // 音频文件压缩处理
        if (Boolean.TRUE.equals(hasCompress)
                && FileUploadUtils.isAllowedExtension(extension, MimeTypeUtils.AUDIO_EXTENSION)) {
            SysFile sysFile = ffmpegProcess.uploadAudio(file);
            return Objects.isNull(sysFile) ? "" : sysFile.getUrl();
        }
        // 图片处理
        return processImage(file, fileName, extension);
    }

    @Override
    public SysFile uploadFileForAudio(MultipartFile file) throws Exception{
        // 文件校验
        FileUploadUtils.assertAllowedWithExt(file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
        // 判定是否为图片,如果是则进行压缩
        String extension = FileTypeUtils.getExtension(file);
        // 音频文件压缩处理
        if (Boolean.TRUE.equals(hasCompress)
                && FileUploadUtils.isAllowedExtension(extension, MimeTypeUtils.AUDIO_EXTENSION)) {
            return ffmpegProcess.uploadAudio(file);
        }
        return null;
    }

    private String processImage(MultipartFile file, String fileName, String extension) throws IOException, ErrorResponseException, InsufficientDataException, InternalException, InvalidKeyException, InvalidResponseException, NoSuchAlgorithmException, ServerException, XmlParserException {
        // 是否允许的格式 && 文件大小判定
        if (Boolean.TRUE.equals(hasCompress)
                && FileUploadUtils.isAllowedExtension(extension, MimeTypeUtils.IMAGE_EXTENSION)
                && isFileSizeOver100KB(file.getSize())) {
            log.info("文件大小：压缩前:{} ", FileUploadUtils.formatFileSize(file.getSize()));
            file = CompressionUtils.compressImg(file);
            // 打印文件大小
            log.info("文件大小：压缩后:{}", FileUploadUtils.formatFileSize(file.getSize()));
        }
        // 获取输入流
        InputStream stream = file.getInputStream();
        PutObjectArgs args = PutObjectArgs.builder()
                .bucket(minioConfig.getBucketName())
                .object(fileName)
                .stream(stream, file.getSize(), -1)
                .contentType(file.getContentType())
                .build();
        client.putObject(args);
        IoUtils.closeQuietly(stream);
        return minioConfig.getBucketName() + "/" + fileName;
    }

    /**
     * 检查文件大小是否超过100KB。
     *
     * @param size 文件大小，单位为字节。
     * @return 如果文件大小超过100KB，则返回true；否则返回false。
     */
    public boolean isFileSizeOver100KB(long size) {
        // 使用BigDecimal进行除法运算，以确保计算结果的精确性
        BigDecimal kb = new BigDecimal(size).divide(BigDecimal.valueOf(KILOBYTE), MathContext.DECIMAL32);
        return kb.doubleValue() > 100;
    }
}
